
import os
import sys

from rpyc.utils.server import ThreadedServer

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

temp_dir = os.path.abspath(__file__)
for i in range(4):
    temp_dir = os.path.dirname(temp_dir)
sys.path.append(temp_dir)
from dexen.system import constants
from dexen.system.server.db_tables import Base, Schema, ScriptSettings,\
                                          PopulationSettings
from dexen.system.server import custom_service
from dexen.system import util

settings_engine = None
SettingsSession = None

class BaseService(custom_service.MyService):
    def on_connect(self):
        self.settings_session = SettingsSession()       
            
    def initialize(self, schema_name=None, pop_name=None, script_name=None):
        self.schema_name = schema_name
        self.pop_name = pop_name
        self.script_name = script_name
        self.pop_settings = self.get_population_obj()
        self.max_individuals = self.pop_settings.max_individuals
        self.script_settings = self.get_script_obj()
        self.ind_table = self.load_ind_table()   
        self.data_structure = self.get_data_structure() 
        
    def get_population_obj(self, schema_name=None, pop_name=None):
        session = self.settings_session

        if not schema_name: schema_name = self.schema_name
        if not pop_name: pop_name = self.pop_name
        
        pop_obj = session.query(PopulationSettings).\
                            filter(PopulationSettings.name == pop_name).\
                            join(Schema).\
                            filter(Schema.name == schema_name).first()
        return pop_obj       
    
    def get_script_obj(self, schema_name=None, pop_name=None, script_name=None):
        session = self.settings_session

        if not schema_name: schema_name = self.schema_name
        if not pop_name: pop_name = self.pop_name
        if not script_name: script_name = self.script_name
        
        script_obj = session.query(ScriptSettings).\
                        join(PopulationSettings).\
                        join(Schema).\
                        filter(Schema.name == schema_name).\
                        filter(PopulationSettings.name == pop_name).\
                        filter(ScriptSettings.name == script_name).first()
        return script_obj  


class FrontendService(BaseService):
    def on_connect(self):
        print "Somebody connected in FrontendService"
        BaseService.on_connect(self)
        
    def on_disconnect(self):
        pass

    def reset_all_databases(self):
        Base.metadata.drop_all(settings_engine)
        Base.metadata.create_all(settings_engine)
    
    def has_schema(self, schema_name):
        print "I am in has_schema"
        schema_names = self.get_schema_names()
        print schema_names
        return schema_name in schema_names
           
    def set_schema(self, schema_name, zip_data, last_modified_time):
        session = self.settings_session
        schema = Schema(schema_name, zip_data, last_modified_time)
        session.add(schema)
        session.commit()
        #util.unzip(zip_data, "server_temp/")
        
    def get_schemas(self):
        session = self.settings_session
        schemas = []
        for schema in session.query(Schema.name, Schema.zip_data, 
                                    Schema.last_modified_time):
            schemas.append(schema)
        session.commit()
        return schemas 
    
    def get_schema(self, schema_name):
        session = self.settings_session
        schema = session.query(Schema.zip_data, Schema.last_modified_time).\
                        filter(Schema.name == schema_name).first()
        session.commit()
        return schema
    
    def get_schema_timestamp(self, schema_name):
        session = self.settings_session
        schema_timestamp = session.query(Schema.last_modified_time).\
                        filter(Schema.name == schema_name).scalar()
        session.commit()
        return schema_timestamp
    
    def get_population_creation_time(self, schema_name, pop_name):
        pop_settings = self.get_population_obj(schema_name, pop_name)
        return pop_settings.creation_time
    
    def get_schema_names(self):
        session = self.settings_session
        schema_names = []
        for schema_name in session.query(Schema.name).order_by(Schema.name):
            schema_names.append(schema_name[0])
        session.commit()
        return schema_names
    
    def stop_population(self, schema_name, pop_name):
        session = self.settings_session
        pop_settings = self.get_population_obj(schema_name, pop_name)
        pop_settings.is_stopped = True
        session.commit()    
    
    def delete_population(self, schema_name, pop_name):
        session = SettingsSession()
        pop_settings = self.get_population_obj(schema_name, pop_name)
        session.delete(pop_settings)
        session.commit()
    
    def stop_script(self, schema_name, pop_name, script_name):
        print "I am stopping the script:", script_name, "*"*10
        script_obj = self.get_script_obj(schema_name, pop_name, script_name)
        session = self.settings_session
        script_obj.is_stopped = True
        session.commit()
    
    def set_population(self, schema_name, pop_name, creation_time):
        session = self.settings_session
        pop_settings = PopulationSettings(pop_name)
        pop_settings.creation_time = creation_time
        schema = session.query(Schema).\
                    filter(Schema.name == schema_name).first()
        pop_settings.schema = schema
        session.add(pop_settings)
        session.commit()
    
    def get_population_names(self, schema_name):
        session = self.settings_session
        schema = session.query(Schema).\
                    filter(Schema.name == schema_name).first()
        pop_names = []
        for pop_settings in schema.populations:
            pop_names.append(pop_settings.name)
        session.commit()
        return pop_names   

    def set_script(self, script_name, file_name, class_name, count=None):
        session = self.settings_session
        pop_settings = self.get_population_obj()
        script_settings = ScriptSettings(script_name, file_name, class_name, 
                                         count)
        script_settings.population_settings = pop_settings
        session.add(script_settings)            
        session.commit()
        
    def get_scripts_info(self, schema_name, pop_name):
        script_names = self.get_script_names(schema_name, pop_name)
        res = {}
        for script_name in script_names:
            script_obj = self.get_script_obj(schema_name, pop_name, script_name)
            res[script_name] = script_obj.get_dict()
        return res

    def get_script_file_names(self, schema_name, pop_name):
        session = self.settings_session
        script_settings = session.query(ScriptSettings).\
                            join(PopulationSettings).join(Schema).\
                            filter(Schema.name == schema_name).\
                            filter(PopulationSettings.name == pop_name).all()
        script_file_names = []
        #print script_settings        
        for script in script_settings:
            script_file_names.append(script.file_name)
        session.commit()
        return script_file_names
    
    def get_script_function_names(self, schema_name, pop_name, file_name):
        session = self.settings_session
        script_settings = session.query(ScriptSettings).\
                            join(PopulationSettings).\
                            join(Schema).\
                            filter(Schema.name == schema_name).\
                            filter(PopulationSettings.name == pop_name).\
                            filter(ScriptSettings.file_name == file_name).all()
        
        script_function_names = []
        for script in script_settings:
            script_function_names.append(script.function_name)
        session.commit()
        return script_function_names
        
    def get_script_names(self, schema_name, pop_name):
        session = self.settings_session
        script_settings = session.query(ScriptSettings).\
                            join(PopulationSettings).join(Schema).\
                            filter(Schema.name == schema_name).\
                            filter(PopulationSettings.name == pop_name).all()
        script_names = []
        
        for script in script_settings:
            script_names.append(script.name)
        session.commit()
        return script_names

def start_services():
    my_server = ThreadedServer(FrontendService, auto_register=True, 
                               protocol_config={
                                 "allow_pickle":True,
                                 "allow_custom_instantiation":True,
                                 "allow_all_attrs":True})
    my_server.start()

def reset_databases():
    Base.metadata.drop_all(settings_engine)
    Base.metadata.create_all(settings_engine)

def initialize_databases():
    global settings_engine, SettingsSession
    config_db = "sqlite:///%s/config.db" %constants.DATABASE_DIR
    settings_engine = create_engine(config_db, echo=False, pool_size=50)
    SettingsSession = sessionmaker(settings_engine)

def main():
    initialize_databases()
    reset_databases()
    start_services()

if __name__ == "__main__":
    main()    
